package utils

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"sync"
)

// 定义全局唯一的管理器实例
var (
	globalWSManager *WebSocketManager
	once            sync.Once // 确保只初始化一次
)

// 通过 GetWebSocketManager 获取全局管理器实例（单例模式）
func GetWebSocketManager() *WebSocketManager {
	once.Do(func() {
		globalWSManager = NewWebSocketManager()
		// 启动管理器（只启动一次）
		go globalWSManager.Run()
	})
	return globalWSManager
}

// Client 表示一个WebSocket客户端
type Client struct {
	ID      string          // 客户端唯一标识
	Conn    *websocket.Conn // WebSocket连接
	Manager *WebSocketManager
	send    chan []byte // 消息发送通道
}

// WebSocketManager 管理所有WebSocket连接
type WebSocketManager struct {
	clients    map[string]*Client // 所有客户端
	register   chan *Client       // 注册通道
	unregister chan *Client       // 注销通道
	mutex      sync.RWMutex       // 保护clients的互斥锁
}

// NewWebSocketManager 创建新的WebSocket管理器
func NewWebSocketManager() *WebSocketManager {
	return &WebSocketManager{
		clients:    make(map[string]*Client),
		register:   make(chan *Client),
		unregister: make(chan *Client),
	}
}

// Run 启动管理器，处理注册、注销和消息发送
func (m *WebSocketManager) Run() {
	for {
		select {
		case client := <-m.register:
			m.mutex.Lock()
			m.clients[client.ID] = client
			log.Printf("客户端 %s 已连接，当前连接数: %d", client.ID, len(m.clients))
			m.mutex.Unlock()
			// 向新连接的客户端发送欢迎消息
			client.send <- []byte("欢迎连接到服务器！您的ID是: " + client.ID)
		case client := <-m.unregister:
			m.mutex.Lock()
			if _, exists := m.clients[client.ID]; exists {
				delete(m.clients, client.ID)
				close(client.send)
				log.Printf("客户端 %s 已断开，当前连接数: %d", client.ID, len(m.clients))
			}
			m.mutex.Unlock()
		}
	}
}

// Broadcast 向所有客户端发送消息
func (m *WebSocketManager) Broadcast(message []byte) {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	for _, client := range m.clients {
		select {
		case client.send <- message:
		default:
			close(client.send)
			delete(m.clients, client.ID)
		}
	}
}

// SendToClient 向特定客户端发送消息
func (m *WebSocketManager) SendToClient(clientID string, message []byte) bool {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	client, exists := m.clients[clientID]
	if !exists {
		log.Println("客户端不存在")
		return false // 客户端不存在
	}
	select {
	case client.send <- message:
		return true // 消息发送成功
	default:
		close(client.send)
		delete(m.clients, client.ID)
		log.Println("消息发送失败")
		return false // 消息发送失败
	}
}

// 配置WebSocket升级器
var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true // 允许跨域
	},
	// 缓冲区配置
	ReadBufferSize:    1024,
	WriteBufferSize:   1024,
	EnableCompression: true, // 压缩（消息较大时启用）
}

// HandleWebSocket 处理WebSocket连接请求
func (m *WebSocketManager) HandleWebSocket(c *gin.Context) {
	// 升级HTTP连接为WebSocket
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Println("升级连接失败:", err)
		return
	}

	// 生成客户端ID（实际应用中可以使用用户ID等唯一标识）
	clientID := c.Query("client_id")
	if clientID == "" {
		// 如果没有提供client_id，生成一个简单的唯一标识
		clientID = generateClientID()
	}
	log.Println("_____clientID:" + clientID)
	// 创建客户端实例
	client := &Client{
		ID:      clientID,
		Conn:    conn,
		Manager: m,
		send:    make(chan []byte, 256),
	}

	// 注册客户端
	m.register <- client

	// 启动读取消息的goroutine
	go client.readPump()
	// 启动写入消息的goroutine
	go client.writePump()
}

// readPump 读取客户端发送的消息
func (c *Client) readPump() {
	defer func() {
		c.Manager.unregister <- c
		c.Conn.Close()
	}()

	for {
		_, message, err := c.Conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("错误: %v", err)
			}
			break
		}

		log.Printf("客户端 %s 发送消息: %s", c.ID, message)

		// 示例：如果消息格式是 "to:目标ID:消息内容"，则转发给目标客户端
		if len(message) > 4 && string(message[:3]) == "to:" {
			parts := bytes.SplitN(message[3:], []byte(":"), 2)
			if len(parts) == 2 {
				targetID := string(parts[0])
				content := parts[1]

				success := c.Manager.SendToClient(targetID, []byte("来自 "+c.ID+": "+string(content)))
				if !success {
					c.send <- []byte("错误: 客户端 " + targetID + " 不存在或已断开连接")
				}
			}
		} else {
			// 否则广播给所有客户端
			c.Manager.Broadcast([]byte(c.ID + " 说: " + string(message)))
		}
	}
}

// writePump 向客户端发送消息
func (c *Client) writePump() {
	defer func() {
		c.Conn.Close()
	}()

	for message := range c.send {
		err := c.Conn.WriteMessage(websocket.TextMessage, message)
		if err != nil {
			break
		}
	}
}

// 生成简单的客户端ID（实际应用中可替换为更可靠的生成方式）
func generateClientID() string {
	b := make([]byte, 8)
	_, err := rand.Read(b)
	if err != nil {
		return "default-client"
	}
	return hex.EncodeToString(b)
}
